// This example blinks leds connected to pins P4, P5, P6, P7 of PCF8574T.
// Button can be connected to other pins and its state observed on SWO.
package main

import (
	"fmt"
	"rtos"

	"stm32/hal/dma"
	"stm32/hal/gpio"
	"stm32/hal/i2c"
	"stm32/hal/irq"
	"stm32/hal/system"
	"stm32/hal/system/timer/rtcst"
)

var (
	leds *gpio.Port
	twi  *i2c.Driver
)

const (
	LED1 = gpio.Pin7
	LED2 = gpio.Pin6
)

func init() {
	system.SetupPLL(8, 1, 72/8)
	rtcst.Setup(32768)

	gpio.B.EnableClock(true)
	leds = gpio.B
	port, pins := gpio.B, gpio.Pin10|gpio.Pin11

	cfg := gpio.Config{Mode: gpio.Out, Speed: gpio.Low}
	leds.Setup(LED1|LED2, &cfg)

	cfg = gpio.Config{
		Mode:   gpio.Alt,
		Driver: gpio.OpenDrain,
	}
	port.Setup(pins, &cfg)
	d := dma.DMA1
	d.EnableClock(true)
	twi = i2c.NewDriver(i2c.I2C2, d.Channel(5, 0), d.Channel(4, 0))
	//twi = i2c.NewDriver(i2c.I2C2)
	twi.P.EnableClock(true)
	rtos.IRQ(irq.I2C2_EV).Enable()
	rtos.IRQ(irq.I2C2_ER).Enable()
	rtos.IRQ(irq.DMA1_Channel4).Enable()
	rtos.IRQ(irq.DMA1_Channel5).Enable()
}

func i2cConfigure() {
	twi.P.Reset() // Mandatory!
	twi.P.Setup(&i2c.Config{Speed: 5000})
	twi.P.Enable()
}

func checkI2CErr(err error) bool {
	if err == nil {
		return true
	}
	if err.(i2c.Error)&i2c.SoftTimeout != 0 {
		fmt.Printf("SoftTimeout\n")
		i2cConfigure()
		return false
	}
	fmt.Printf("Error: 0x%02x\n", err)
	twi.P.SoftReset()
	return false
}

func main() {
	i2cConfigure()
	c := twi.MasterConn(0x27, i2c.NOAS)

	out := []byte{
		0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
		0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
		0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf,
		0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf,
		0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
		0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
		0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
		0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
		0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
		0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
		0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
		0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
		0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf,
		0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf,
		0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
		0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
	}
	var led bool
	for {
		if led {
			leds.SetPins(LED1)
			led = false
		} else {
			leds.ClearPins(LED1)
			led = true
		}
		_, err := c.Write(out)
		if !checkI2CErr(err) {
			continue
		}
		_, err = c.Write(out)
		if !checkI2CErr(err) {
			continue
		}
		var in [4]byte
		n, err := c.Read(in[:4])
		fmt.Printf("%2x\n", in[:n])
		if !checkI2CErr(err) {
			continue
		}
		c.SetStopRead()
		n, err = c.Read(in[:3])
		fmt.Printf("%2x\n", in[:n])
		if !checkI2CErr(err) {
			continue
		}
	}
}

func twiISR() {
	twi.I2CISR()
}
func twiRxDMAISR() {
	twi.DMAISR(twi.RxDMA)
}

func twiTxDMAISR() {
	twi.DMAISR(twi.TxDMA)
}

//emgo:const
//c:__attribute__((section(".ISRs")))
var ISRs = [...]func(){
	irq.RTCAlarm:      rtcst.ISR,
	irq.I2C2_EV:       twiISR,
	irq.I2C2_ER:       twiISR,
	irq.DMA1_Channel4: twiTxDMAISR,
	irq.DMA1_Channel5: twiRxDMAISR,
}
